<?php
namespace app\common\controller;

use \app\scodetrace\encoder\TcodeEncoder;
use \app\scodetrace\encoder\PcodeEncoder;

/**
 * there are two things this class do,the first one is to store a data set,which will apply when the code is scanned,the second one is the common execute entry,you should not changed it. and you must add your custom function in the derive class.
 * in order to implements step one, you should call _dataStore() to finish the operate,the function require a function name which will be invoked when the exec interface is invoking.
 * and the second step will invoke the function which is assigned in the step one.
 *
 * the api usage:
 *   step one: invoke store data type interface
 *   step two: invoke exec interface to actually do work.
 */
class ScannerBase extends \app\common\controller\ApiPublic {
  /**
   * the base function to store the data, and the data will be stored in the cache,then return a token,
   * this token will be used by invoke the function which invoke _dataDo()
   * @param  Array $fields     the fields will be gotten in the request parameter.
   * @param  String $do_funname when the
   * @return [type]             [description]
   */
  protected function _dataStore($fields,$do_funname=null) {
    if (!$do_funname) {
      return json_pack(['token'=>null],400);
    }
    $data = [];
    $data['_do'] = $do_funname;
    foreach ($fields as $v)
      $data[$v] = $this->param($v);
    $token = md5(implode(',', $data));
    cache('Scanner_'.$token,$data,3600,'SCANNER');
    return json_pack(['token'=>$token,'submitter' => model('admin/AdminUser')->get($GLOBALS['userInfo']['uid'])->getAttr('real_name')]);
  }

  /**
   * this is the base function for step two, all the operate will call this function to exec,
   * the function had done permission check, and forbidden the illegal operation,you should use this function as unique entry.
   * a function which is called in the function should declare like this:
   *             private function do_xxx($data)
   * you should return a response, and this response will send back to user directly.
   * @return Response the Response will be back to user,you should make a response in the derive function.
   */
  public function exec() {
    if (!($token = $this->param('token'))) {
      return json_pack('你需要传入一个token', 400);
    }
    if (!($cache=cache('Scanner_'.$token))) {
      return json_pack('无效的token', 400);
    }
    $isComplete = $this->param('is_complete', false);

    $request = $this->request;
    $funname = $cache['_do'];
    unset($cache['_do']);
    $UserInfo = $GLOBALS['userInfo'];
    if (!in_array(0,$UserInfo['gids'], true))
      if (!AuthAdapter::checkRule(strtolower($request->module().'.'.$request->controller().'.'.$funname), $UserInfo))
        return json_pack("你没有执行权限",STATUS_AUTH_FAIL);

    if (method_exists($this, $funname)) {
      if ($code = $this->parseCode($isComplete)) {
        return $this->$funname($cache, $code);
      } else {
        return json_pack('传入的码（溯源码/装箱码）有误', 400);
      }
    } else {
      return json_pack('后端那家伙写代码又走神了（快去提醒他）', 400);
    }
  }

  //todo update cache
  /**
   * This function will get code in the request parameter automatically,this is a tool function, you can implement the do_xx function without using it.
   * the type of codes is supported as follow:
   *   tcode (trace code)
   *   pcode (packing code)
   *   code (ambiguous type code, the function will tried to parse it,but it must contain one kind of code)
   * @param  Boolean $isComplete
   * @return Array the code information,consist of two parts,there are type and ids.
   */
  protected function parseCode($isComplete = true) {
    if ($tmp = $this->param('tcodes')) {
      if (is_string($tmp)) {
        $tmp = explode(',', $tmp);
      }
      if ($tmp = TcodeEncoder::getInstance()->decode($tmp)) {
        if ($tmp['error'] && $isComplete)
          return null;
        return ['type'=>'tcode','ids'=>$tmp];
      }
    } else if ($tmp = $this->param('pcodes')) {
      if (is_string($tmp)) {
        $tmp = explode(',', $tmp);
      }
      if ($tmp = PcodeEncoder::getInstance()->decode($tmp)) {
        if ($tmp['error'] && $isComplete)
          return null;
        return ['type'=>'pcode','ids'=>$tmp];
      }
    } else if ($tmp = $this->param('codes')) {
      if (is_string($tmp)) {
        $tmp = explode(',', $tmp);
      }
      if ($tmp = TcodeEncoder::getInstance()->decode($tmp)) {
        if ($tmp['error'] && $isComplete)
          return null;
        return ['type'=>'tcode','ids'=>$tmp];
      }
      if ($tmp = PcodeEncoder::getInstance()->decode($tmp)) {
        if ($tmp['error'] && $isComplete)
          return null;
        return ['type'=>'pcode','ids'=>$tmp];
      }
    }
    return null;
  }
}

?>